﻿using Module.Test.Domain.Models.Grpc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;

namespace Module.Test.Application.GrpcServices
{

    public sealed class PersonService : IPersonService
    {
        public async Task<Person> Get(CancellationToken token = default)
        {
            //await Task.Delay(TimeSpan.FromMilliseconds(100), token);
            var personFullName = "test name";
            var personDateOfBirth = DateTime.Now.AddYears(-30).Date;
            var personAddress = new Address
            {
                City = "test city name",
                Country = "test country name",
                PostCode = "test 12345",
                Street = "test street name"
            };
            return new Person
            {
                FullName = personFullName,
                DateOfBirth = personDateOfBirth,
                Addresses = new[] { personAddress }
            };
        }
        public async Task<int> GetInt(CancellationToken token = default)
        {
            return await Task.FromResult(10);
        }

        public async Task<Person> CreatePersonAsync(string fullName, DateTime dateOfBirth, IList<Address> addresses, CancellationToken token)
        {
            await Task.Delay(TimeSpan.FromMilliseconds(100), token);

            return new Person
            {
                FullName = fullName,
                DateOfBirth = dateOfBirth,
                Addresses = addresses
            };
        }



        public async Task<Person> FindPersonOlderThan(IAsyncEnumerable<Person> persons, TimeSpan age, CancellationToken token)
        {
            await foreach (var person in persons.WithCancellation(token))
            {
                if ((DateTime.Now - person.DateOfBirth) > age)
                {
                    return person;
                }
            }

            return null;
        }

        public async IAsyncEnumerable<Person> GetRandomPersons(int count, TimeSpan minAge, [EnumeratorCancellation] CancellationToken token)
        {
            await Task.Delay(TimeSpan.FromMilliseconds(100), token);

            for (var i = 0; i < count; i++)
            {
                yield return new Person
                {
                    DateOfBirth = DateTime.Now.AddDays(-i) - minAge,
                    FullName = Guid.NewGuid().ToString()
                };
            }
        }


        public async Task<(int Count, Address Address, IAsyncEnumerable<Person> Persons)> GetListOfStreetResidents(string country, string city, string street, CancellationToken token)
        {
            await Task.Delay(TimeSpan.FromMilliseconds(100), token);

            var count = 3;
            var address = new Address
            {
                City = city,
                Country = country,
                Street = street
            };

            var persons = CreateStreetResidents(count, address, token);
            return (count, address, persons);
        }



        public async IAsyncEnumerable<Person> FindPersonsYoungerThan(IAsyncEnumerable<Person> persons, TimeSpan age, [EnumeratorCancellation] CancellationToken token)
        {
            await foreach (var person in persons.WithCancellation(token))
            {
                if ((DateTime.Now - person.DateOfBirth) < age)
                {
                    yield return person;
                }
            }
        }


        private static async IAsyncEnumerable<Person> CreateStreetResidents(int top, Address address, [EnumeratorCancellation] CancellationToken token)
        {
            for (var i = 0; i < top; i++)
            {
                await Task.Delay(TimeSpan.FromMilliseconds(100), token);

                yield return new Person
                {
                    FullName = Guid.NewGuid().ToString(),
                    Addresses = new[] { address }
                };
            }
        }

    }
}
